package org.maplanning.feature.rect;

import java.util.ArrayList;

import org.maplanning.GridMap;
import org.maplanning.env.Area;

public class RectRoomFeature {
	/** First index is axis, second index is range (0 -> min, 1 -> max) */
	private Area room;
	private ArrayList<Door> doors = new ArrayList<Door>();

	public boolean detect(GridMap grid, int[] x) {
		room = new Area(x);
		findWall(grid, x, 0, -1);
		findWall(grid, x, 0, 1);
		findWall(grid, x, 1, -1);
		findWall(grid, x, 1, 1);
		findDoors(grid, room.getBoundMin(), 0, room.getBoundMax()[0]);
		findDoors(grid, room.getBoundMin(), 1, room.getBoundMax()[1]);
		findDoors(grid, room.getBoundMax(), 0, room.getBoundMin()[0]);
		findDoors(grid, room.getBoundMax(), 1, room.getBoundMin()[1]);
		return true;
	}

	/**
	 *
	 * @param grid
	 * @param x
	 * @param movementAxis 0 or 1
	 * @param increment -1 or 1
	 */
	private void findWall(GridMap grid, int[] x, int movementAxis, int increment) {
		int fixedAxis = 1 - movementAxis;
		int stepCount = 0;
		int maxSteps = 500;
		int radius = 2;
		int[] pos = x.clone();
		for ( ; stepCount < maxSteps ; pos[movementAxis] += increment, stepCount++) {
			int[] t = pos.clone();
			int wallCount = 0;
			for ( t[fixedAxis] += -radius ; t[fixedAxis] <= pos[fixedAxis] + radius ; t[fixedAxis]++) {
				if (!grid.isValidCoordinate(t)) {
					wallCount++; // count out-of-map coordinates as walls 
					continue;
				}
				int tile = grid.get(t);
				if (tile == GridMap.WALL) {
					wallCount++;
				}
			}
			// check that there are enough wall tiles:
			if ( wallCount >= (radius-1)*2+1 ) {
				room.expandTo(pos);
				return;
			}
			
		}
	}

	private void findDoors(GridMap grid, int[] xStart, int movementAxis, int xEnd) {
		xStart = xStart.clone();
		int increment = (int) Math.signum(xEnd - xStart[movementAxis]);
		if (increment == 0) {
			return;
		}
		Door door = null;
		for ( ; xStart[movementAxis] * increment < xEnd * increment ; xStart[movementAxis] += increment) {
			int tile = grid.get(xStart);
			if ( tile != GridMap.WALL ) {
				if (door == null) {
					int fixedAxis = 1 - movementAxis;
					int[] exitDirection = {0, 0};
					exitDirection[fixedAxis] = xStart[fixedAxis] == room.getBoundMin()[fixedAxis] ? -1 : 1;
					door = new Door(xStart, exitDirection);
				} else {
					door.expandTo(xStart);
				}
			} else {
				if (door != null) {
					doors.add(door);
					door = null;
				}
			}
		}
		if (door != null) {
			doors.add(door);
		}
	}

	public Area getRoom() {
		return room;
	}

	public ArrayList<Door> getDoors() {
		return doors;
	}

}
